//
//  HMUserAccountViewModel.swift
//  SinaWeibo
//
//  Created by apple on 16/9/25.
//  Copyright © 2016年 itcast. All rights reserved.
//  视图模型有可能是 单例对象有可能只是单纯的对象
//  viewmodel: 负责请求网络数据 , 封装数据处理的逻辑 数据的缓存    -> 给控制器减肥

import UIKit

private let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last! as NSString).appendingPathComponent("account.plist")
//有且只能够有一个用处处于登陆状态
class HMUserAccountViewModel: NSObject {
    
    //单例对象
    static let sharedAccountViewModel: HMUserAccountViewModel = HMUserAccountViewModel()
    
    //先不要关注给userAccount 赋值 一会详细讲
    /*
    赋值有两种情况
     1. 用户未登陆 -> 输入用户名,密码 -> 授权 -> 截取code -> code 换token, 获取用户信息 -> 给用户信息赋值
     2. 用户已经登陆,第二次打开应用的时候 -> 从沙盒中获取用户信息  -> 给 userAccount赋值
     */
    var userAccount: HMUserAccount? {
        didSet {
            //一旦外界给userAccount 赋值的时候就立即给iconURL 赋值,就能够确保iconURL一定有值
            let urlString = userAccount?.avatar_large ?? ""
            iconURL = URL(string: urlString)
        }
    }
    
    
    //判断用户是否登录
    //计算性属性 和 一个有返回值的方法类似
    var userLogin: Bool {
        if userAccount?.access_token != nil && isExpires == false {
            return true
        }
        
        //默认用户是未登录
        return false
    }
    
    
    //可以使用计算性属性 计算型属性的特点是相当于一个方法 每次执行都会调用 消耗cpu  值如果需要一直变化 就需要使用计算型属性
    //存储型的属性 调用存储型的属性的时候 实际上回直接读取内存 不消耗cpu 但是消耗内存 值一旦设置就不需要变化 就可以使用 存储型属性
    var iconURL: URL?
    
    
    //判断用户token是否过期
    var isExpires: Bool {
        
        //判断当前日期 和过期日期比较 如果 当前日期小于过期日期 就是 没有过期   2016 9 20 < 2016 9 28
        // 2016 9 28   2016 9 20
        if userAccount?.expires_date?.compare(Date()) == ComparisonResult.orderedDescending {
            //没有过期
            return false
        }
        //默认过期
        return true
    }
    
    
    override init() {
        super.init()
        //从沙盒中获取数据保存在单例对象的模型中
        //在构造函数中给属性赋值 不会执行到 didSet
        self.userAccount = self.loadUserAccount()
        let urlString = userAccount?.avatar_large ?? ""
        iconURL = URL(string: urlString)
    }
    
    internal func loadAccessToken(code: String,finished: @escaping (Bool) -> ()) {
        let urlString = "https://api.weibo.com/oauth2/access_token"
        let parameters = ["client_id" : client_id,
                          "client_secret" : client_secret,
                          "grant_type" : "authorization_code",
                          "code" : code,
                          "redirect_uri" : redirect_uri
        ]
        //利用网络请求框架 请求接口 POST
        HMNetworkTools.sharedTools.request(method: .POST, urlString: urlString, parameters: parameters) { (responseObject, error) in
            if error != nil {
                //统一输出
                //执行失败的回调
                finished(false)
                return
            }
            
            print(responseObject)
            
            //请求用户信息 实际上就是在一个网络请求的回调中 发起另外一个网络请求
            self.loadUserInfo(dict: responseObject as! [String : Any],finished: finished)
            
        }
    }
    
    
    private func loadUserInfo(dict: [String : Any],finished: @escaping (Bool) -> ()) {
        let urlString = "https://api.weibo.com/2/users/show.json"
        let access_token = dict["access_token"]!
        let uid = dict["uid"]!
        //字典中不能添加nil
        let paramters = ["access_token" : access_token,
                         "uid" : uid]
        HMNetworkTools.sharedTools.request(method: .GET, urlString: urlString, parameters: paramters) { (responseObject, error) in
            if error != nil {
                //统一输出
                finished(false)
                return
            }
            
            //获取用户信息 将字典类型的用户信息 转换成模型数据 -> 将模型数据存储在本地(归档)
            //字典转模型
            var userInfoDict = responseObject as! [String : Any]
            
            //合并字典
            for keyValues in dict {
                userInfoDict[keyValues.key] = keyValues.value
            }
            
            //字典转模型
            let userAccount = HMUserAccount(dict: userInfoDict)
            print(userAccount)
            
            //用用户模型数据存储在本地 方便以后使用
            self.saveUserAccount(userAccount: userAccount)
            
            //从未登陆状态 到登陆状态 不需要从沙盒中获取用户信息
            //赋值还可以解决后面的一个bug
            self.userAccount = userAccount
            //在这个地方弹出登录成功的窗口吗?
            //执行成功的回调
            finished(true)
            
        }
    }
    
    //通过归档的方式来存数据
    private func saveUserAccount(userAccount: HMUserAccount)  {
        //一般归档在沙盒的Document
        //拼接文件名的方法String 没有 需要将 String 转换为 NSStirng
        //使用默认 as 转换的前提是 被转换的对象不是可选类型
        //将某一个对象归档到某一个路径下
        NSKeyedArchiver.archiveRootObject(userAccount, toFile: path)
        //打印存储路径
        print(path)
    }
    
    //从沙盒中加载用户信息
    private func loadUserAccount() -> HMUserAccount? {
        let userAccount = NSKeyedUnarchiver.unarchiveObject(withFile: path) as? HMUserAccount
        return userAccount
    }
    
}
